package com.zzh.zzhaiagent.wx.service;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zzh.zzhaiagent.domain.entity.UserProfiles;
import com.zzh.zzhaiagent.service.IUserProfilesService;
import com.zzh.zzhaiagent.websocket.service.WebSocketService;
import com.zzh.zzhaiagent.wx.utils.TextBuilder;
import jakarta.annotation.Resource;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.apache.catalina.User;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

/**
 * @author: zzh
 * @date: 2024/12/18 14:41:01
 * @version: 1.0
 */
//微信服务实现类
@Service
public class WxMsgServiceImpl implements WxMsgService {

    @Resource
    @Lazy
    private WebSocketService webSocketService;
//
    @Resource
    private IUserProfilesService userService;

    // 授权链接 注意替换为自己的appid和redirect_uri授权成功回调的地址,以及scope=snsapi_userinfo
    // 注意：这里的redirect_uri需要在微信公众平台中配置，并且需要在微信公众平台中配置授权成功回调的地址
    public static final String URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";

    @Value("${wx.mp.callback}")
    private String callback;

//    @Resource
//    private UserDao userDao;

    /**
     * 扫码触发
     * @param wxMpService
     * @param wxMpXmlMessage
     * @return
     */
    @Override
    public WxMpXmlOutMessage scan(WxMpService wxMpService, WxMpXmlMessage wxMpXmlMessage) throws UnsupportedEncodingException {
        // 获取用户的openId
        String openId = wxMpXmlMessage.getFromUser();
        // 对code进行处理，因为关注和扫码的code是不一样的，所以需要区分
        String code = wxMpXmlMessage.getEventKey();
        Integer loginCode = getEventKey(code);//这里的code值就是二维码携带的code
        System.out.println("loginCode：" + loginCode + "，code：" + code);

//        // 判断这个用户是否注册过 根据openId查询用户
        UserProfiles user =  userService.getOne(new LambdaQueryWrapper<UserProfiles>().eq(UserProfiles::getOpenId, openId));
        boolean registered = ObjectUtil.isNotNull(user);
        // 如果用户用微信登录授权过 用户用微信登录过，直接不需要点击登录授权，直接登录成功
        if (registered) {
            // 直接返回消息 走登录成功，用code找到channel推送消息
            webSocketService.scanLoginSuccess(loginCode,user.getId());
            return TextBuilder.build("登录成功，AI应用正在为您服务", wxMpXmlMessage, wxMpService);
        }

        // 生成一个uuid，用于保存openId和code
        String uuid = StrUtil.uuid();
        // 保存uuid和openId的映射关系
        // 同时channel形式推送消息给前端，提示等待用户授权登录
        webSocketService.saveUUIDWxInfoOpenId(openId,uuid);

        // 扫码事件处理
        // 拼接授权url
        // 保存openId和code，用于授权成功后拿到code
        // 同时channel形式推送消息给前端，提示等待用户授权登录
        // 发送回前端去进行更新二维码显示状态，让前端去显示等待用户授权登录
        webSocketService.sendMsgWaitUserClickAuth(loginCode,uuid,openId);


        String encode = URLEncoder.encode(callback + "/api/wx/portal/public/callBack", "UTF-8");
        String authorizeUrl = String.format(URL, wxMpService.getWxMpConfigStorage().getAppId(), encode);
        // 封装url让用户点击登录请求，(其实请求就是去拿到用户信息！)并且授权
        return TextBuilder.build("请点击链接授权：<a href=\"" + authorizeUrl + "\">登录</a>", wxMpXmlMessage, wxMpService);
    }

    @Override
    public void authorize(WxOAuth2UserInfo userInfo) {
        // 授权成功后，将用户信息保存起来
        webSocketService.saveUUIDWxInfoOther(userInfo);

        // 根据openId拿到code，最终拿到channel
        Integer codeByOpenId = webSocketService.getCodeByOpenId(userInfo.getOpenid());
        // 返回消息 走登录成功并需要认证邮箱
        webSocketService.verifyEmail(codeByOpenId);
    }

    private Integer getEventKey(String code) {
        if (code == null){
            return null;
        }
        return Integer.parseInt(code.replace("qrscene_", ""));
    }
}
